Tal Benavidor contributes support for Columbus/Visiontac v900.
authorrobertl <robertl>
Sat, 18 Apr 2009 20:04:52 +0000 (20:04 +0000)
committerrobertl <robertl>
Sat, 18 Apr 2009 20:04:52 +0000 (20:04 +0000)
Makefile.in
reference/v900_advanced_mode.csv [new file with mode: 0644]
reference/v900_advanced_mode.gpx [new file with mode: 0644]
reference/v900_basic_mode.csv [new file with mode: 0644]
reference/v900_basic_mode.gpx [new file with mode: 0644]
testo
v900.c [new file with mode: 0644]
vecs.c
xmldoc/formats/v900.xml [new file with mode: 0644]

index 18b858972a1492955d702d13776cfedc56bc82d1..6e072854a8431b5ee47d550efb54fe467b3975fa 100644 (file)
@@ -61,7 +61,8 @@ ALL_FMTS=$(MINIMAL_FMTS) gtm.o gpsutil.o pcx.o cetus.o copilot.o \
        ggv_log.o g7towin.o garmin_gpi.o lmx.o random.o xol.o dg-100.o \
        navilink.o mtk_logger.o ik3d.o osm.o destinator.o exif.o vidaone.o \
        igo8.o gopal.o humminbird.o mapasia.o gnav_trl.o navitel.o ggv_ovl.o \
-       jtr.o sbp.o sbn.o mmo.o skyforce.o itracku.o pocketfms_bc.o pocketfms_fp.o
+       jtr.o sbp.o sbn.o mmo.o skyforce.o itracku.o v900.o \
+       pocketfms_bc.o pocketfms_fp.o
 
 FMTS=@FMTS@
 
diff --git a/reference/v900_advanced_mode.csv b/reference/v900_advanced_mode.csv
new file mode 100644 (file)
index 0000000..8a4666b
Binary files /dev/null and b/reference/v900_advanced_mode.csv differ
diff --git a/reference/v900_advanced_mode.gpx b/reference/v900_advanced_mode.gpx
new file mode 100644 (file)
index 0000000..6221c15
--- /dev/null
@@ -0,0 +1,226 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gpx
+  version="1.0"
+  creator="GPSBabel - http://www.gpsbabel.org"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xmlns="http://www.topografix.com/GPX/1/0"
+  xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd">
+<time>1970-01-01T00:00:00Z</time>
+<bounds minlat="31.765526000" minlon="35.207726000" maxlat="31.769621000" maxlon="35.208829000"/>
+<trk>
+  <name>V900 tracklog</name>
+  <desc>V900 GPS tracklog data</desc>
+<trkseg>
+<trkpt lat="31.769598000" lon="35.208829000">
+  <ele>787.000000</ele>
+  <time>2009-02-04T06:38:21Z</time>
+  <course>318.000000</course>
+  <speed>5.555555</speed>
+  <fix>3d</fix>
+  <hdop>1.100000</hdop>
+  <vdop>0.900000</vdop>
+  <pdop>1.400000</pdop>
+</trkpt>
+<trkpt lat="31.769621000" lon="35.208773000">
+  <ele>787.000000</ele>
+  <time>2009-02-04T06:38:22Z</time>
+  <course>295.000000</course>
+  <speed>6.111111</speed>
+  <fix>3d</fix>
+  <hdop>1.000000</hdop>
+  <vdop>0.800000</vdop>
+  <pdop>1.300000</pdop>
+</trkpt>
+<trkpt lat="31.769616000" lon="35.208683000">
+  <ele>787.000000</ele>
+  <time>2009-02-04T06:38:23Z</time>
+  <course>266.000000</course>
+  <speed>7.500000</speed>
+  <fix>3d</fix>
+  <hdop>1.000000</hdop>
+  <vdop>0.800000</vdop>
+  <pdop>1.300000</pdop>
+</trkpt>
+<trkpt lat="31.769610000" lon="35.208568000">
+  <ele>786.000000</ele>
+  <time>2009-02-04T06:38:24Z</time>
+  <course>266.000000</course>
+  <speed>9.722222</speed>
+  <fix>3d</fix>
+  <hdop>1.000000</hdop>
+  <vdop>0.800000</vdop>
+  <pdop>1.300000</pdop>
+</trkpt>
+<trkpt lat="31.769596000" lon="35.208435000">
+  <ele>786.000000</ele>
+  <time>2009-02-04T06:38:25Z</time>
+  <course>264.000000</course>
+  <speed>12.222222</speed>
+  <fix>3d</fix>
+  <hdop>1.000000</hdop>
+  <vdop>0.800000</vdop>
+  <pdop>1.300000</pdop>
+</trkpt>
+<trkpt lat="31.769574000" lon="35.208294000">
+  <ele>786.000000</ele>
+  <time>2009-02-04T06:38:26Z</time>
+  <course>261.000000</course>
+  <speed>13.333333</speed>
+  <fix>3d</fix>
+  <hdop>1.000000</hdop>
+  <vdop>0.800000</vdop>
+  <pdop>1.300000</pdop>
+</trkpt>
+<trkpt lat="31.765536000" lon="35.207726000">
+  <ele>772.000000</ele>
+  <time>2009-02-04T06:26:22Z</time>
+  <course>0.000000</course>
+  <speed>0.000000</speed>
+  <fix>3d</fix>
+  <hdop>1.700000</hdop>
+  <vdop>1.000000</vdop>
+  <pdop>2.000000</pdop>
+</trkpt>
+<trkpt lat="31.765534000" lon="35.207726000">
+  <ele>772.000000</ele>
+  <time>2009-02-04T06:26:23Z</time>
+  <course>0.000000</course>
+  <speed>0.000000</speed>
+  <fix>3d</fix>
+  <hdop>1.700000</hdop>
+  <vdop>1.000000</vdop>
+  <pdop>2.000000</pdop>
+</trkpt>
+<trkpt lat="31.765534000" lon="35.207726000">
+  <ele>772.000000</ele>
+  <time>2009-02-04T06:26:24Z</time>
+  <course>0.000000</course>
+  <speed>0.000000</speed>
+  <fix>3d</fix>
+  <hdop>1.700000</hdop>
+  <vdop>1.000000</vdop>
+  <pdop>2.000000</pdop>
+</trkpt>
+<trkpt lat="31.765534000" lon="35.207728000">
+  <ele>772.000000</ele>
+  <time>2009-02-04T06:26:25Z</time>
+  <course>0.000000</course>
+  <speed>0.000000</speed>
+  <fix>3d</fix>
+  <hdop>1.700000</hdop>
+  <vdop>1.000000</vdop>
+  <pdop>2.000000</pdop>
+</trkpt>
+<trkpt lat="31.765533000" lon="35.207728000">
+  <ele>772.000000</ele>
+  <time>2009-02-04T06:26:26Z</time>
+  <course>0.000000</course>
+  <speed>0.000000</speed>
+  <fix>2d</fix>
+  <hdop>1.900000</hdop>
+  <vdop>1.000000</vdop>
+  <pdop>2.100000</pdop>
+</trkpt>
+<trkpt lat="31.765533000" lon="35.207728000">
+  <ele>772.000000</ele>
+  <time>2009-02-04T06:26:27Z</time>
+  <course>0.000000</course>
+  <speed>0.000000</speed>
+  <fix>2d</fix>
+  <hdop>1.900000</hdop>
+  <vdop>1.000000</vdop>
+  <pdop>2.100000</pdop>
+</trkpt>
+<trkpt lat="31.765533000" lon="35.207728000">
+  <ele>772.000000</ele>
+  <time>2009-02-04T06:26:28Z</time>
+  <course>0.000000</course>
+  <speed>0.000000</speed>
+  <fix>2d</fix>
+  <hdop>1.900000</hdop>
+  <vdop>1.000000</vdop>
+  <pdop>2.100000</pdop>
+</trkpt>
+<trkpt lat="31.765531000" lon="35.207730000">
+  <ele>772.000000</ele>
+  <time>2009-02-04T06:26:29Z</time>
+  <course>0.000000</course>
+  <speed>0.000000</speed>
+  <fix>2d</fix>
+  <hdop>1.900000</hdop>
+  <vdop>1.000000</vdop>
+  <pdop>2.100000</pdop>
+</trkpt>
+<trkpt lat="31.765531000" lon="35.207730000">
+  <ele>772.000000</ele>
+  <time>2009-02-04T06:26:30Z</time>
+  <course>0.000000</course>
+  <speed>0.000000</speed>
+  <fix>2d</fix>
+  <hdop>1.900000</hdop>
+  <vdop>1.000000</vdop>
+  <pdop>2.100000</pdop>
+</trkpt>
+<trkpt lat="31.765530000" lon="35.207730000">
+  <ele>772.000000</ele>
+  <time>2009-02-04T06:26:31Z</time>
+  <course>0.000000</course>
+  <speed>0.000000</speed>
+  <fix>2d</fix>
+  <hdop>1.900000</hdop>
+  <vdop>1.000000</vdop>
+  <pdop>2.100000</pdop>
+</trkpt>
+<trkpt lat="31.765530000" lon="35.207730000">
+  <ele>772.000000</ele>
+  <time>2009-02-04T06:26:32Z</time>
+  <course>0.000000</course>
+  <speed>0.000000</speed>
+  <fix>3d</fix>
+  <hdop>1.800000</hdop>
+  <vdop>1.000000</vdop>
+  <pdop>2.100000</pdop>
+</trkpt>
+<trkpt lat="31.765530000" lon="35.207730000">
+  <ele>772.000000</ele>
+  <time>2009-02-04T06:26:33Z</time>
+  <course>0.000000</course>
+  <speed>0.000000</speed>
+  <fix>2d</fix>
+  <hdop>1.900000</hdop>
+  <vdop>1.000000</vdop>
+  <pdop>2.100000</pdop>
+</trkpt>
+<trkpt lat="31.765528000" lon="35.207730000">
+  <ele>772.000000</ele>
+  <time>2009-02-04T06:26:34Z</time>
+  <course>0.000000</course>
+  <speed>0.000000</speed>
+  <fix>2d</fix>
+  <hdop>1.900000</hdop>
+  <vdop>1.000000</vdop>
+  <pdop>2.100000</pdop>
+</trkpt>
+<trkpt lat="31.765528000" lon="35.207731000">
+  <ele>772.000000</ele>
+  <time>2009-02-04T06:26:35Z</time>
+  <course>0.000000</course>
+  <speed>0.000000</speed>
+  <fix>2d</fix>
+  <hdop>1.900000</hdop>
+  <vdop>1.000000</vdop>
+  <pdop>2.100000</pdop>
+</trkpt>
+<trkpt lat="31.765526000" lon="35.207731000">
+  <ele>772.000000</ele>
+  <time>2009-02-04T06:26:36Z</time>
+  <course>0.000000</course>
+  <speed>0.000000</speed>
+  <fix>2d</fix>
+  <hdop>1.900000</hdop>
+  <vdop>1.000000</vdop>
+  <pdop>2.100000</pdop>
+</trkpt>
+</trkseg>
+</trk>
+</gpx>
diff --git a/reference/v900_basic_mode.csv b/reference/v900_basic_mode.csv
new file mode 100644 (file)
index 0000000..38c4d19
Binary files /dev/null and b/reference/v900_basic_mode.csv differ
diff --git a/reference/v900_basic_mode.gpx b/reference/v900_basic_mode.gpx
new file mode 100644 (file)
index 0000000..8bab687
--- /dev/null
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gpx
+  version="1.0"
+  creator="GPSBabel - http://www.gpsbabel.org"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xmlns="http://www.topografix.com/GPX/1/0"
+  xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd">
+<time>1970-01-01T00:00:00Z</time>
+<bounds minlat="31.765973000" minlon="35.206728000" maxlat="31.766553000" maxlon="35.206901000"/>
+<trk>
+  <name>V900 tracklog</name>
+  <desc>V900 GPS tracklog data</desc>
+<trkseg>
+<trkpt lat="31.765973000" lon="35.206901000">
+  <ele>827.000000</ele>
+  <time>2009-04-04T06:35:10Z</time>
+  <course>357.000000</course>
+  <speed>3.333333</speed>
+</trkpt>
+<trkpt lat="31.766016000" lon="35.206889000">
+  <ele>827.000000</ele>
+  <time>2009-04-04T06:35:11Z</time>
+  <course>354.000000</course>
+  <speed>3.888889</speed>
+</trkpt>
+<trkpt lat="31.766056000" lon="35.206885000">
+  <ele>827.000000</ele>
+  <time>2009-04-04T06:35:12Z</time>
+  <course>353.000000</course>
+  <speed>4.444445</speed>
+</trkpt>
+<trkpt lat="31.766106000" lon="35.206883000">
+  <ele>827.000000</ele>
+  <time>2009-04-04T06:35:13Z</time>
+  <course>355.000000</course>
+  <speed>5.000000</speed>
+</trkpt>
+<trkpt lat="31.766163000" lon="35.206873000">
+  <ele>827.000000</ele>
+  <time>2009-04-04T06:35:14Z</time>
+  <course>353.000000</course>
+  <speed>5.555555</speed>
+</trkpt>
+<trkpt lat="31.766216000" lon="35.206864000">
+  <ele>828.000000</ele>
+  <time>2009-04-04T06:35:15Z</time>
+  <course>352.000000</course>
+  <speed>5.555555</speed>
+</trkpt>
+<trkpt lat="31.766271000" lon="35.206851000">
+  <ele>828.000000</ele>
+  <time>2009-04-04T06:35:16Z</time>
+  <course>350.000000</course>
+  <speed>5.555555</speed>
+</trkpt>
+<trkpt lat="31.766326000" lon="35.206833000">
+  <ele>828.000000</ele>
+  <time>2009-04-04T06:35:17Z</time>
+  <course>347.000000</course>
+  <speed>5.555555</speed>
+</trkpt>
+<trkpt lat="31.766376000" lon="35.206816000">
+  <ele>828.000000</ele>
+  <time>2009-04-04T06:35:18Z</time>
+  <course>344.000000</course>
+  <speed>5.555555</speed>
+</trkpt>
+<trkpt lat="31.766421000" lon="35.206798000">
+  <ele>828.000000</ele>
+  <time>2009-04-04T06:35:19Z</time>
+  <course>342.000000</course>
+  <speed>4.444445</speed>
+</trkpt>
+<trkpt lat="31.766458000" lon="35.206778000">
+  <ele>828.000000</ele>
+  <time>2009-04-04T06:35:20Z</time>
+  <course>336.000000</course>
+  <speed>3.888889</speed>
+</trkpt>
+<trkpt lat="31.766504000" lon="35.206761000">
+  <ele>827.000000</ele>
+  <time>2009-04-04T06:35:21Z</time>
+  <course>312.000000</course>
+  <speed>3.888889</speed>
+</trkpt>
+<trkpt lat="31.766535000" lon="35.206743000">
+  <ele>827.000000</ele>
+  <time>2009-04-04T06:35:22Z</time>
+  <course>313.000000</course>
+  <speed>3.333333</speed>
+</trkpt>
+<trkpt lat="31.766553000" lon="35.206728000">
+  <ele>827.000000</ele>
+  <time>2009-04-04T06:35:23Z</time>
+  <course>306.000000</course>
+  <speed>3.055556</speed>
+</trkpt>
+</trkseg>
+</trk>
+</gpx>
diff --git a/testo b/testo
index 7804e4774b2a93a0cc65e2df6e3583dcd1e6c777..749b8e58d42291f196f5223670b8c20d17c68855 100755 (executable)
--- a/testo
+++ b/testo
@@ -1585,5 +1585,12 @@ bincompare ${REFERENCE}/pocketfms_bc.babel ${TMPDIR}/pocketfms_bc
 gpsbabel -i pocketfms_fp -f ${REFERENCE}/pocketfms_fp.xml -o gpx -F ${TMPDIR}/pocketfms_fp.gpx
 compare ${REFERENCE}/pocketfms_fp.gpx ${TMPDIR}/pocketfms_fp.gpx
 
+#
+# Columbus/Visiontac V900 "binary" csv files
+#
+gpsbabel -i v900 -f ${REFERENCE}/v900_basic_mode.csv -o gpx -F ${TMPDIR}/v900_basic_mode.gpx
+compare ${REFERENCE}/v900_basic_mode.gpx ${TMPDIR}/v900_basic_mode.gpx
+gpsbabel -i v900 -f ${REFERENCE}/v900_advanced_mode.csv -o gpx -F ${TMPDIR}/v900_advanced_mode.gpx
+compare ${REFERENCE}/v900_advanced_mode.gpx ${TMPDIR}/v900_advanced_mode.gpx
 
 exit 0
diff --git a/v900.c b/v900.c
new file mode 100644 (file)
index 0000000..0dd0ba1
--- /dev/null
+++ b/v900.c
@@ -0,0 +1,365 @@
+/* 
+       Support for Columbus/Visiontac V900 csv format
+        This format pads fields with NULL up to a fixed per field length.
+        Because of that, and because xcsv does not allows a regex as a field delimiter,
+        a special c module is required.
+
+       Copyright (C) 2009 Tal Benavidor
+
+       This program is free software; you can redistribute it and/or modify
+       it under the terms of the GNU General Public License as published by
+       the Free Software Foundation; either version 2 of the License, or
+       (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+       TODO:
+               - support way points
+               - QUESTION: course = heading ??
+                - HEIGHT: Altitude in meters (not corrected to WGS84...) ??
+ */
+
+/******************************************************************************
+ FILE FORMAT INFO
+=================
+
+File has csv extention, and is somewhat csv like creature...
+All lines end with \r\n
+First line is a header line. It contains no nulls.
+Following lines are record lines. They are comma separated, but fields always
+have the exact same length (per field), and therfore, the commas are always
+at the exact same position on the line. Fields are padded with nulls, in case
+they hace shorter value then the fixed field length.
+Two modes availe: basic and advanced.
+
+The following two examples show "*" where null appears.
+
+------basic mode - start------------------------- 
+INDEX,TAG,DATE,TIME,LATITUDE N/S,LONGITUDE E/W,HEIGHT,SPEED,HEADING,VOX
+1*****,T,090404,063401,31.765931N,035.206969E,821**,0***,0**,*********
+2*****,T,090404,063402,31.765931N,035.206969E,821**,0***,0**,*********
+3*****,T,090404,063403,31.765933N,035.206971E,821**,0***,0**,*********
+4*****,T,090404,063404,31.765933N,035.206971E,822**,0***,0**,*********
+5*****,T,090404,063407,31.765934N,035.206971E,824**,0***,0**,*********
+------basic mode - end--------------------------- 
+
+
+------advanced mode - start------------------------- 
+INDEX,TAG,DATE,TIME,LATITUDE N/S,LONGITUDE E/W,HEIGHT,SPEED,HEADING,FIX MODE,VALID,PDOP,HDOP,VDOP,VOX
+1*****,T,090204,055722,31.768380N,035.209656E,149**,0***,0**,3D,SPS ,2.6**,2.4**,1.0**,*********
+2*****,T,090204,055723,31.768380N,035.209656E,149**,0***,0**,3D,SPS ,2.5**,2.3**,0.9**,*********
+3*****,T,090204,055724,31.768378N,035.209658E,149**,0***,0**,3D,SPS ,2.5**,2.3**,0.9**,*********
+4*****,T,090204,055725,31.768378N,035.209658E,149**,0***,0**,3D,SPS ,2.5**,2.3**,0.9**,*********
+5*****,T,090204,055728,31.768376N,035.209660E,150**,0***,0**,3D,SPS ,2.5**,2.3**,0.9**,*********
+6*****,T,090204,055729,31.768376N,035.209660E,150**,0***,0**,3D,SPS ,4.0**,2.8**,2.9**,*********
+7*****,T,090204,055730,31.768376N,035.209661E,150**,0***,0**,3D,SPS ,2.5**,2.3**,0.9**,*********
+8*****,T,090204,055731,31.768376N,035.209661E,150**,0***,0**,3D,SPS ,2.5**,2.3**,0.9**,*********
+9*****,T,090204,055737,31.768326N,035.209993E,150**,0***,0**,3D,SPS ,2.5**,2.3**,0.9**,*********
+10****,T,090204,055738,31.768339N,035.209976E,153**,0***,0**,3D,SPS ,2.5**,2.3**,0.9**,*********
+11****,T,090204,055739,31.768338N,035.209991E,155**,0***,0**,3D,SPS ,2.5**,2.3**,0.9**,*********
+------advanced mode - end--------------------------- 
+
+for a little more info, see structures: 
+       one_line_advanced_mode, one_line_basic_mode, one_line_common_start.
+******************************************************************************/
+
+#include "defs.h"
+#include <stdio.h>
+#include <assert.h>
+
+
+/* the start of each record (line) is common to both advanced and basic mode.
+   it will be parsed by a single common code. hence, it will be easier and clearer
+   to have a common structure for it.
+ */
+struct one_line_common_start
+{
+       char index[6];          /* record number */
+       char comma1;            /* ',' */
+       char tag;               /* tag type. T=trackpoint. TODO: more options??? */
+       char comma2;            /* ',' */
+       char date[6];           /* YYMMDD. YY=09 is 2009. */
+       char comma3;            /* ',' */
+       char time[6];           /* HHMMSS */
+       char comma4;            /* ',' */
+       char latitude_num[9];   /* example: "31.768380" */
+       char latitude_NS;       /* 'N' or 'S' */
+       char comma5;            /* ',' */
+       char longitude_num[10]; /* example: "035.209656" */
+       char longitude_EW;      /* 'E' or 'W' */
+       char comma6;            /* ',' */
+       char height[5];         /* Altitude in meters.
+                                 * (not corrected to WGS84 ??) */
+       char comma7;            /* ',' */
+       char speed[4];          /* speed in km/h. no decimal point. */
+       char comma8;            /* ',' */
+       char heading[3];        /* heading in degrees */
+       char comma9;            /* ',' */
+};
+
+/* this structure holds one record (line) in advanced logging mode.
+   advanced mode lines looks like this ('*' means NULL):
+1717**,T,090204,062634,31.765528N,035.207730E,772**,0***,0**,2D,SPS ,2.1**,1.9**,1.0**,*********
+*/
+struct one_line_advanced_mode
+{
+       struct one_line_common_start common;
+       char fixmode[2]; /* "2D" or "3D" */
+       char comma10;    /* ',' */
+       char valid[4];   /* "SPS " or "DGPS" */
+       char comma11;    /* ',' */
+       char pdop[5];
+       char comma12;    /* ',' */
+       char hdop[5];
+       char comma13;    /* ',' */
+       char vdop[5];
+       char comma14;    /* ',' */
+       char vox[9];     /* voicetag recorded */
+       char cr;         /* '\r' */
+       char lf;         /* '\n' */
+};
+
+/* this structure holds one record (line) in basic logging mode.
+   basic mode lines looks like this ('*' means NULL):
+1*****,T,090404,063401,31.765931N,035.206969E,821**,0***,0**,*********
+*/
+struct one_line_basic_mode
+{
+       struct one_line_common_start common;
+       char vox[9];    /* voicetag recorded */
+       char cr;        /* '\r' */
+       char lf;        /* '\n' */
+};
+
+
+static FILE* fin = NULL;
+
+/* copied from dg-100.cpp */
+static void
+v900_log(const char *fmt, ...)
+{
+       va_list ap;
+       va_start (ap, fmt);
+
+       if (global_opts.debug_level < 1) {
+               return;
+       }
+       vfprintf(stderr, fmt, ap);
+       va_end(ap);
+}
+
+static void
+v900_rd_init(const char *fname)
+{
+       v900_log("%s(%s)\n",__func__,fname);
+        /* note: file is opened in binary mode, since lines end with \r\n, and in windows text mode
+           that will be translated to a single \n, making the line len one character shorter than
+           on linux machines.
+         */
+       fin = fopen(fname,"rb");
+        if (!fin)
+               fatal("v900: could not open '%s'.\n", fname);
+}
+
+static void
+v900_rd_deinit(void)
+{
+       v900_log("%s\n",__func__);
+       if (fin)
+               fclose(fin);
+}
+
+
+/* copied from dg-100.c - slight (incompatible) modification to how the date parameter is used */
+static time_t
+bintime2utc(int date, int time)
+{
+       struct tm gpstime;
+
+       gpstime.tm_sec   = time % 100;
+       time /= 100;
+       gpstime.tm_min   = time % 100;
+       time /= 100;
+       gpstime.tm_hour  = time;
+
+       /*
+        * GPS year: 2000+; struct tm year: 1900+
+        * GPS month: 1-12, struct tm month: 0-11
+        */
+       gpstime.tm_mday  = date % 100;
+       date /= 100;
+       gpstime.tm_mon   = date % 100 - 1;
+       date /= 100;
+       gpstime.tm_year  = date + 100;
+
+       return(mkgmtime(&gpstime));
+}
+
+static void
+v900_read(void)
+{
+       /* use line buffer large enough to hold either basic or advanced mode lines. */
+        union
+       {
+               struct one_line_basic_mode    bas;
+               struct one_line_advanced_mode adv;
+               char text[200]; /* used to read the header line, which is normal text */
+       } line;
+       int is_advanced_mode = 0;
+       route_head *track;
+
+       v900_log("%s\n",__func__);
+
+/*
+Basic mode:    INDEX,TAG,DATE,TIME,LATITUDE N/S,LONGITUDE E/W,HEIGHT,SPEED,HEADING,VOX
+Advanced mode: INDEX,TAG,DATE,TIME,LATITUDE N/S,LONGITUDE E/W,HEIGHT,SPEED,HEADING,FIX MODE,VALID,PDOP,HDOP,VDOP,VOX
+*/
+       /* first, determine if this is advanced mode by reading the first line.
+           since the first line does not contain any nulls, it can be safely read by fgets(). */
+       if (!fgets(line.text, sizeof(line), fin))
+               fatal("v900: error reading header (first) line from input file\n");
+       is_advanced_mode = (NULL != strstr(line.text,"PDOP")); /* PDOP field appears only in advanced mode */
+
+       v900_log("header line: %s",line);
+       v900_log("is_advance_mode=%d\n",is_advanced_mode);
+
+       track = route_head_alloc();
+       track->rte_name = xstrdup("V900 tracklog");
+       track->rte_desc = xstrdup("V900 GPS tracklog data");
+       track_add_head(track);
+
+       while (1)
+       {
+               waypoint *wpt;
+               char c;
+               int record_len = is_advanced_mode ? sizeof(line.adv) : sizeof(line.bas);
+               if (fread ( &line, record_len, 1, fin ) != 1)
+               {
+                       break;
+               }
+
+               /* change all "," characters to NULLs.
+                   so every field is null terminated.
+                 */
+               assert(line.bas.common.comma1==',');  // TODO: abort with fatal()
+               assert(line.bas.common.comma2==',');
+               assert(line.bas.common.comma3==',');
+               assert(line.bas.common.comma4==',');
+               assert(line.bas.common.comma5==',');
+               assert(line.bas.common.comma6==',');
+               assert(line.bas.common.comma7==',');
+               assert(line.bas.common.comma8==',');
+               assert(line.bas.common.comma9==',');
+               line.bas.common.comma1 = 0;
+               line.bas.common.comma2 = 0;
+               line.bas.common.comma3 = 0;
+               line.bas.common.comma4 = 0;
+               line.bas.common.comma5 = 0;
+               line.bas.common.comma6 = 0;
+               line.bas.common.comma7 = 0;
+               line.bas.common.comma8 = 0;
+               line.bas.common.comma9 = 0;
+               if(is_advanced_mode)
+               {
+                       /* change all "," characters to NULLs.
+                          so every field is null terminated.
+                        */
+                       assert(line.adv.comma10==','); // TODO: abort with fatal()
+                       assert(line.adv.comma11==',');
+                       assert(line.adv.comma12==',');
+                       assert(line.adv.comma13==',');
+                       assert(line.adv.comma14==',');
+                       assert(line.adv.cr=='\r');
+                       assert(line.adv.lf=='\n');
+                       line.adv.comma10 = 0;
+                       line.adv.comma11 = 0;
+                       line.adv.comma12 = 0;
+                       line.adv.comma13 = 0;
+                       line.adv.comma14 = 0;
+                       line.adv.cr = 0;        /* null terminate vox field */
+
+               }
+               else
+               {
+                       assert(line.bas.cr=='\r');
+                       assert(line.bas.lf=='\n');
+                       line.bas.cr = 0;        /* null terminate vox field */
+               }
+
+               wpt = waypt_new();
+
+               /* lat is a string in the form: 31.768380N */
+               c = line.bas.common.latitude_NS;        /* N/S */
+               assert(c == 'N' || c == 'S');
+               wpt->latitude = atof(line.bas.common.latitude_num);
+               if (c == 'S')
+                       wpt->latitude = -wpt->latitude;
+
+               /* lon is a string in the form: 035.209656E */
+               c = line.bas.common.longitude_EW; /* get E/W */
+               assert(c == 'E' || c == 'W');
+               line.bas.common.longitude_EW = 0; /* the E will confuse atof(), if not removed */
+               wpt->longitude = atof(line.bas.common.longitude_num);
+               if (c == 'W')
+                       wpt->longitude = -wpt->longitude;
+
+               wpt->altitude = atoi(line.bas.common.height);
+
+               /* handle date/time fields */
+               {
+                 int date, time;
+                 date = atoi(line.bas.common.date);
+                 time = atoi(line.bas.common.time);
+                 wpt->creation_time = bintime2utc(date, time);
+               }
+
+               wpt->speed = KPH_TO_MPS(atoi(line.bas.common.speed));
+               wpt->wpt_flags.speed = 1;
+
+               wpt->course = atoi(line.bas.common.heading);
+               wpt->wpt_flags.course = 1;
+
+               if(is_advanced_mode)
+               {
+                       wpt->hdop = atof(line.adv.hdop);
+                       wpt->vdop = atof(line.adv.vdop);
+                       wpt->pdop = atof(line.adv.pdop);
+
+                       /* handle fix mode (2d, 3d, etc.) */
+                       if (!strcmp(line.adv.valid,"DGPS"))
+                               wpt->fix = fix_dgps;
+                       else if (!strcmp(line.adv.fixmode,"3D"))
+                               wpt->fix = fix_3d;
+                       else if (!strcmp(line.adv.fixmode,"2D"))
+                               wpt->fix = fix_2d;
+                       else
+                               /* possible values: fix_unknown,fix_none,fix_2d,fix_3d,fix_dgps,fix_pps */
+                               wpt->fix = fix_unknown;
+               }
+
+               track_add_wpt(track, wpt);
+       }
+}
+
+ff_vecs_t v900_vecs = {
+       ff_type_file,
+       {ff_cap_read, ff_cap_read, ff_cap_none}, /* Read only format. May only read trackpoints and waypoints. */
+       v900_rd_init,
+       NULL,          /* wr_init */
+       v900_rd_deinit,
+       NULL,          /* wr_deinit */
+       v900_read,
+       NULL,          /* write */
+       NULL, 
+       NULL,          /* args */
+       CET_CHARSET_UTF8, 1,    /* Could be  US-ASCII, since we only read "0-9,A-Z\n\r" */
+       {NULL,NULL,NULL,NULL,NULL,NULL}
+};
+
diff --git a/vecs.c b/vecs.c
index 9c6c7d8adf6b079e900f90e2706d1e8f04a62789..dd9e3514641c81755d0769fc4ca9d93ea1424ec7 100644 (file)
--- a/vecs.c
+++ b/vecs.c
@@ -156,6 +156,7 @@ extern ff_vecs_t sbp_vecs;
 extern ff_vecs_t sbn_vecs;
 extern ff_vecs_t mmo_vecs;
 extern ff_vecs_t skyforce_vecs;
+extern ff_vecs_t v900_vecs;
 extern ff_vecs_t pocketfms_bc_vecs;
 extern ff_vecs_t pocketfms_fp_vecs;
 
@@ -912,6 +913,12 @@ vecs_t vec_list[] = {
                "PocketFMS flightplan",
                NULL
         },
+        {
+               &v900_vecs,
+               "v900",
+               "Columbus/Visiontac V900 files (.csv)",
+               NULL
+        },
         
 
 #endif // MAXIMAL_ENABLED
diff --git a/xmldoc/formats/v900.xml b/xmldoc/formats/v900.xml
new file mode 100644 (file)
index 0000000..3cc9189
--- /dev/null
@@ -0,0 +1,16 @@
+<para>Read only support for csv file format used by <productname>Visiontac VGPS-900</productname> or <productname>Columbus V-900</productname> GPS data loggers. These seem to be two brand names for the exact same product.</para>
+
+<para>The the V-900 stores logs in on a microSD in a custom csv format. This format contains NULL chracters and fiexed length fields, and therefore can not  handled by the normal csv module in GPSBabel.</para>
+
+<para>
+<ulink url="http://www.visiontac.com/v900_specs.htm">Visiontac VGPS-900</ulink>
+</para>
+
+<example id="v900">
+  <title>Command convertion of a v900 csv log file to a gpx format</title>
+  <para><userinput>gpsbabel -i v900 -f 09040400.csv -o gpx -F outfile.gpx</userinput></para>
+</example>
+
+<para>
+The device support logging of track points, way points, and voice recordings (.wav files). Currently only track points are supported.
+</para>